﻿#ifndef Config_h__2013_8_29__12_13
#define Config_h__2013_8_29__12_13


#include "df.h"
#include "Reflection.h"


namespace df
{
	typedef std::map<String, String>  MapStr;

	namespace ConfigSymbol
	{
		const TCHAR charSymbol = tt_('\'');
		const TCHAR keySymbol = tt_('"');
		const TCHAR objSymbol1 = tt_('{');
		const TCHAR objSymbol2 = tt_('}');

		const TCHAR assSymbol = tt_('=');

		const TCHAR arraySymbol1 = tt_('[');
		const TCHAR arraySymbol2 = tt_(']');
		const TCHAR arraySplitSymbol = tt_(',');

		const int stackSize = 128;
	}

	class Config
	{
	public:


		static const TCHAR * tabChar()
		{
			return tt_("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
		}

		//*******************************************
		// Summary : 将map反射为object
		// Parameter - StrMap & fromMap : 待反射的map
		// Parameter - T & toObj : 包含元数据的对象
		//*******************************************
		template<class T>
		static void MapToObject(MapStr & fromMap, T & toObj)
		{
			static_assert(Reflection<T>::Support, "Object does not support Reflection (need META_DATA_INIT)");

			EnumMetaMember<T>::Start(MapStrToObjectLoop<T>({ fromMap, toObj }));
		}

		//*******************************************
		// Summary : 将object反射为map
		// Parameter - T & fromObj : 
		// Parameter - StrMap & toMap : 
		//*******************************************
		template<class T>
		static void ObjectToMap(T & fromObj, MapStr & toMap)
		{
			static_assert(Reflection<T>::Support, "Object does not support Reflection (need META_DATA_INIT)");

			toMap.clear();

			EnumMetaMember<T>::Start(ObjToMapStrLoop<T>({ toMap, fromObj }));
		}


		//*******************************************
		// Summary : 将ini文件内容反射至obj
		// Parameter - const df::CC & fileName : 文件名
		// Parameter - OT & obj : 目标对象
		//*******************************************
		template<class OT>
		static void Read(const df::CC & fileName, OT & obj, df::ErrWrap err = nullptr)
		{
			File file;
			if (!file.Open(fileName))
				return;

			if (file.GetFileSize() == 0)
				return;

			String resBuf;

			file.ReadToString(resBuf);

			uint8_t bomLen = file.CheckBOM(resBuf) / sizeof(TCHAR);

			ReadToFromStr(df::CC(&resBuf[0] + bomLen, resBuf.length() - bomLen)
				, &obj
				, &df::Reflection<OT>::GetAssignFuncMap()
				, &df::Reflection<OT>::GetCompositionMemberFuncMap()
				, err
				);
		}

		//*******************************************
		// Summary : 将obj反射至ini文件
		// Parameter - const df::CC & fileName : 文件名
		// Parameter - OT & obj : 
		// Returns - bool : 
		//*******************************************
		template<class OT>
		static void Write(const df::CC & fileName, OT & obj)
		{
			File file;

			if (!file.Open(fileName, true, true))
				return;

			String resBuf;
			String valBuf;

			EnumMetaMember<OT>::Start(ObjToFileLoop<OT>({ resBuf, obj, valBuf }));

			file.Write(resBuf);
		}



		//*******************************************
		// Summary : 将s中的charSymbol号转义为charSymbolcharSymbol
		// Parameter - const String & s : 
		// Parameter - String & val_ : 储存结果
		//*******************************************
		static void Transferred(const df::CC & s, String & val_)
		{
			val_ += ConfigSymbol::charSymbol;

			for (intptr_t i = 0; i < s.Length(); i++)
			{
				TCHAR c = s[i];
				//转义"
				if (c == ConfigSymbol::charSymbol)
					val_ += ConfigSymbol::charSymbol;
				val_ += c;
			}
			val_ += ConfigSymbol::charSymbol;
		}

	private:
		//*******************************************
		// Summary : 解析配置文件
		//*******************************************
		inline static void ReadToFromStr(const df::CC & str, void * objPtr0
			, df::AssignFuncMap * assignMap0, df::CompositionMemberFuncMap * compMap0, df::ErrWrap err)
		{

			void* objPtrStack[ConfigSymbol::stackSize];
			df::AssignFuncMap * assMapStack[ConfigSymbol::stackSize];
			df::CompositionMemberFuncMap * compMapStack[ConfigSymbol::stackSize];

			if (objPtr0 == nullptr || assignMap0 == nullptr || compMap0 == nullptr)
			{
				DF_ERRLOG(err, df::ErrCode::IllegalNull, tcc_("ReadToFromStr非法null参数!"));
				return;
			}


			String key, val_;
			const TCHAR * res = str.char_;
			intptr_t resLength = str.length_;

			objPtrStack[0] = objPtr0;
			assMapStack[0] = assignMap0;
			compMapStack[0] = compMap0;

			int stackI = 0;

			int lineNum = 1;


			for (intptr_t i = 0; i < resLength; i++)
			{
				TCHAR c = res[i];

				if (c == 32 || c == tt_('\r') || c == 9)
					continue;

				if (c == ConfigSymbol::assSymbol)
				{
					//=号出现在首部或多次出现,错误格式,跳过此行
					if (val_.length() == 0 || key.length() > 0)
					{
						lineNum++;
						for (i++; i < resLength && res[i] != tt_('\n'); i++);
						val_.clear();
						key.clear();
						continue;
					}
					val_.swap(key);
					continue;
				}

				//解析完一行
				if (c == tt_('\n'))
				{

					lineNum += 1;
					if (key.length() > 0)
					{
						DF_ASSERT(objPtrStack[stackI] != nullptr);
						DF_ASSERT(assMapStack[stackI] != nullptr);
						auto itm = assMapStack[stackI]->find(key);
						if (itm != assMapStack[stackI]->end())
							itm->second(objPtrStack[stackI], val_);
					}

					val_.clear();
					key.clear();
					continue;
				}


				//字串
				if (c == ConfigSymbol::charSymbol && key.length() != 0)
				{
					for (i++; i < resLength; i++)
					{
						c = res[i];

						if (c == tt_('\n')) {
							lineNum += 1;
						}

						if (c == ConfigSymbol::charSymbol)//转义字符,或结束
						{
							if (i + 1 < resLength && res[i + 1] == ConfigSymbol::charSymbol)
							{
								val_ += ConfigSymbol::charSymbol;
								i++;
							}
							else
								break;
						}
						else
							val_ += c;
					}
					continue;
				}


				//注释,跳过此行
				if (c == tt_(';') && val_.length() == 0 && key.length() == 0)
				{
					lineNum += 1;
					for (i++; i < resLength && res[i] != tt_('\n'); i++);
					continue;
				}

				//复合对象
				if (c == ConfigSymbol::objSymbol1)
				{
					if (stackI >= ConfigSymbol::stackSize - 1) {
						DF_ERRLOG(err, df::ErrCode::StackOverflow, tcc_("最多支持128个子类型嵌套!"));
						return;
					}

					if (key.length() < 1) {
						DF_ERRLOG(err, df::ErrCode::SynatxError, tcc_("嵌套类型没有键值, 行号：") << lineNum);
						return;
					}

					auto it = compMapStack[stackI]->find(key);
					if (it != compMapStack[stackI]->end())
					{
						compMapStack[stackI + 1] =
							(df::CompositionMemberFuncMap *) it->second(objPtrStack[stackI]
								, assMapStack[stackI + 1], objPtrStack[stackI + 1]);
						stackI += 1;
					}

					val_.clear();
					key.clear();
					continue;
				}

				if (c == ConfigSymbol::objSymbol2)
				{
					if (stackI < 1) {
						DF_ERRLOG(err, df::ErrCode::SynatxError, tcc_("发现多余}号,行号：") << lineNum);
						return;
					}

					stackI -= 1;
					val_.clear();
					key.clear();
					continue;
				}

				//大写转小写
				//if (key.Length() == 0 && c >= t_t('A') && c <= t_t('Z'))
				//c += 32;
				val_ += c;
			}

			if (key.length() > 0)
			{
				DF_ASSERT(objPtrStack[stackI] != nullptr);
				DF_ASSERT(assMapStack[stackI] != nullptr);
				auto itm = assMapStack[stackI]->find(key);
				if (itm != assMapStack[stackI]->end())
					itm->second(objPtrStack[stackI], val_);
			}
		}


		template<class T>
		struct MapStrToObjectLoop
		{
			MapStr & map_;
			T & obj_;

			template<int I>
			void operator()()
			{
				auto it = map_.find(obj_.DF_TEMPLATE Get_Member_Name<I>());
				if (it != map_.end())
				{
					StrToVar(it->second
						, obj_.DF_TEMPLATE Get_Member<I>());
				}

			}
		};

		template<class T>
		struct ObjToMapStrLoop
		{
			MapStr & map_;
			T & obj_;


			template<int I>
			void operator()()
			{
				VarToStr(obj_.DF_TEMPLATE Get_Member<I>()
					, map_[obj_.DF_TEMPLATE Get_Member_Name<I>()]);
			}
		};


		//数字类型直接转为字串
		template<bool IsIntegral>
		struct EachObjToFile
		{
			template<int I, class ParaT>
			static void Start(ParaT & obj)
			{
				obj.conf_ << CC(Config::tabChar(), obj.tabSize) << obj.obj_.DF_TEMPLATE Get_Member_Name<I>()
					<< ConfigSymbol::assSymbol
					<< obj.obj_.DF_TEMPLATE Get_Member<I>() << tcc_("\r\n");
			}
		};

		//处理每个成员
		template<class T, int TabSize_ = 0>
		struct ObjToFileLoop
		{
			//生成结果字串
			String & conf_;
			T & obj_;
			String & val;

			enum
			{
				tabSize = TabSize_
			};

			static_assert(tabSize < ConfigSymbol::stackSize, "too much class nesting");

			//复合成员
			template<int I, class MT>
			void Assign(typename MT::template Get_Member_Type<I>::container::compositionType)
			{
				typedef typename T::DF_TEMPLATE Get_Member_Type<I>::type ValT;


				//写入节名
				conf_ << CC(tabChar(), tabSize) << obj_.DF_TEMPLATE Get_Member_Name<I>()
					<< tcc_(" = {\r\n");


				//递归复合成员
				EnumMetaMember<ValT>::Start(ObjToFileLoop<ValT, tabSize + 1>({ conf_, obj_.DF_TEMPLATE Get_Member<I>(), val }));


				conf_ << CC(Config::tabChar(), tabSize) << tcc_("}\r\n");
			}

			//vector成员
			template<int I, class MT>
			void Assign(typename MT::template Get_Member_Type<I>::container::vectorType)
			{
				// 				typedef typename T::DF_TEMPLATE Get_Member_Type<I>::type ValT;
				// 
				// 				auto & vect = obj_.DF_TEMPLATE Get_Member<I>();
				// 
				// 				//写入节名
				// 				conf_ << CC(tabChar(), tabSize) << obj_.DF_TEMPLATE Get_Member_Name<I>()
				// 					<<assSymbol<< tcc_(" ")<<arraySymbol1<<tcc_("\r\n");
				// 
				// 				for (auto & v : vect)
				// 				{
				// 					ObjToFileLoop<ValT::value_type, tabSize>({ conf_ ,v,val });
				// 					conf_ << arraySplitSymbol;
				// 				}
				// 
				// 
				// 				//递归复合成员
				// 				EnumMetaMember<ValT>::Start(ObjToFileLoop<ValT, tabSize + 1>({ conf_, obj_.DF_TEMPLATE Get_Member<I>(), val }));
				// 
				// 
				// 				conf_ << CC(Config::tabChar(), tabSize) << arraySymbol1 << tcc_("\r\n");
			}

			//普通成员
			template<int I, class MT>
			void Assign(...)
			{
				typedef typename T::DF_TEMPLATE Get_Member_Type<I>::type ValT;

				EachObjToFile
					<
					std::is_integral<ValT>::value
					|| std::is_same<float, ValT>::value
					|| std::is_same<double, ValT>::value
					> ::DF_TEMPLATE Start<I>(*this);
			}

			template<int I>
			void operator()()
			{
				Assign<I, T>(1);
			}
		};


	private:

		Config(const Config& cp);
		Config& operator = (const Config& cp);
	};

	//字串类型需转义
	template<>
	struct Config::EachObjToFile<false>
	{
		template<int I, class ParaT>
		static void Start(ParaT & obj)
		{
			obj.val.clear();

			VarToStr(obj.obj_.DF_TEMPLATE Get_Member<I>()
				, obj.val);

			obj.conf_ << CC(Config::tabChar(), obj.tabSize) << obj.obj_.DF_TEMPLATE Get_Member_Name<I>()
				<< tcc_(" = ");

			Transferred(obj.val, obj.conf_);

			obj.conf_ << tcc_("\r\n");
		}
	};

};



#endif // Config_h__2013_8_29__12_13
